package gui;

import gui.junitTestViewer.TestViewer;
import gui.mainFrame.MainFrame;
import gui.mainFrame.TestConditionBtnPanel;
import gui.mainFrame.MenuBar;
import gui.mainFrame.codeViewer.CodeViewer;
import gui.mainFrame.TestCreatorBtnPanel;
import gui.mainFrame.testConditionViewer.TestConditionViewer;
import gui.help.AboutBox;
import gui.mainFrame.testConditionViewer.branchViewer.BranchGraphController;
import gui.mainFrame.testCreator.TestCreator;
import gui.projectSetup.ProjectConfigurationWindow;
import gui.testSetup.components.TestConfSetting;
import gui.testSetup.NewTestWizard;
import gui.testSetup.SetupEditor;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import testGenerator.Controller;

/**
 * This class provides access to select functionality in other GUI components.
 * @author William Whitney
 */
public class GUIController
{

    private MenuBar menuBar;
    private CodeViewer codeViewer;
    private TestConditionBtnPanel conditionViewerBtnBar;
    private TestCreatorBtnPanel testCreatorBtnPanel;
    private static Controller controller;
    private MainFrame mainFrame;
    private TestConditionViewer pathEditor;
    private TestCreator testCreator;
    private BranchGraphController branchPathController;
    private File directoryPath;

    /**
     * Default constructor.
     */
    public GUIController()
    {
        controller = new Controller(this);
        branchPathController = new BranchGraphController(this, controller);
        directoryPath = new File("");
    }

    /**
     * Makes the tool visible.
     */
    public void showUI()
    {
        this.mainFrame = new MainFrame(this);
        this.menuBar = new MenuBar(this, controller);
        this.mainFrame.setMenuBar(menuBar);
        showCodeViewer();
        showPathEditor();
        this.mainFrame.showUI();
        this.setIsBeforeWizardRun(true);

    }

    /**
     * Used to disable menu bar, edit menu and path editor
     * until after the user selects a source file.
     * @param val
     */
    public void setIsBeforeWizardRun(Boolean val)
    {

        //Disable Edit Menu
        this.menuBar.disableEditMenuOptions(val);
        this.conditionViewerBtnBar.disableBtns(val);
    }

    /**
     * Makes the code viewer visible
     */
    private void showCodeViewer()
    {
        this.codeViewer = new CodeViewer(this);
        this.mainFrame.setCodeEditor(codeViewer);
    }

    /**
     * Tells the code viewer to show the current version of the source code.
     */
    public void showCode()
    {
        this.codeViewer.setCode(controller.getSourceCode());
    }

    /**
     * Tells the gui to show the execution path editor.
     */
    public void showPathEditor()
    {
        this.conditionViewerBtnBar = new TestConditionBtnPanel(controller, this);
        this.pathEditor = new TestConditionViewer(controller, this);
        this.mainFrame.setEditor(this.pathEditor);
        this.mainFrame.setButtonNavBar(this.conditionViewerBtnBar);
        
    }

     /**
     * Tells the gui to update button panel with file path label.
     */
    public void updateFilePath()
    {
        this.conditionViewerBtnBar = new TestConditionBtnPanel(controller, this);
        this.mainFrame.setButtonNavBar(this.conditionViewerBtnBar);
    }
    
    /**
     * Tells the gui to show the test creator.
     */
    public void showTestCreator()
    {
        this.testCreatorBtnPanel = new TestCreatorBtnPanel(controller, this);
        this.testCreator = new TestCreator(controller, this);
        this.mainFrame.setEditor(this.testCreator);
        this.mainFrame.setButtonNavBar(this.testCreatorBtnPanel);
        highlightLine();
    }

    /**
     * Tells the gui to launch the new test wizard.
     */
    public void showNewTestWizard()
    {
        try {
        new NewTestWizard(this, controller).showUI();
        
        } catch (FileNotFoundException ex) {
            JOptionPane.showMessageDialog(null, "Your project is not configured! Please configure"
                    + " your project first.", "Error", JOptionPane.ERROR_MESSAGE);
            
        }
        catch (IOException e) {
            Logger.getLogger(NewTestWizard.class.getName()).log(Level.SEVERE, null, e);
            
        }
    }

    /**
     * Tells the execution path editor to update.
     */
    public void updateExecutionPathEditor()
    {

        this.pathEditor.updateView();
        this.branchPathController.render();

    }

    /**
     * Launches the JUnit test viewer.
     */
    public void showTestViewer()
    {
        //Verify that all branches have tests
        if (controller.isAllBranchesTested())
        {
            //Print all tests without asking if complete
            new TestViewer(controller, controller.generateJUnitTest(true));
        }
        else
        {
            //Ask user if they want to print stubs
            String message = "Not all tests are complete!\n"
                    + "Do you want to generate stubs for incomplete test branches?";
            int response = JOptionPane.showConfirmDialog(
                    mainFrame,
                    message,
                    "Test Generation Warning",
                    JOptionPane.YES_NO_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE);

            if (response != JOptionPane.CANCEL_OPTION)
            {
                boolean printStubs = (response == JOptionPane.YES_OPTION);
                new TestViewer(controller, controller.generateJUnitTest(printStubs));
            }
        }

    }

    /**
     * Launches the about box.
     */
    public void showAboutBox()
    {
        AboutBox about = new AboutBox();
        about.showUI();
    }

    /**
     * Launches the user guide.
     */
    public void showUserGuide()
    {
        String url = "https://sourceforge.net/apps/trac/amaticjunittool/wiki/User%20Guide";
        try
        {
            java.awt.Desktop.getDesktop().browse(java.net.URI.create(url));
        }
        catch (Exception error)
        {
            error.printStackTrace();
        }
    }

    /**
     * Launches window to show JUnit test setup.
     */
    public void showTestSetup()
    {
        SetupEditor setup = new SetupEditor(controller, TestConfSetting.SET_UP_METHOD);
        setup.showUI();
    }

    /**
     * Launches window to show JUnit test teardown.
     */
    public void showTestTeardown()
    {
        SetupEditor tearDown = new SetupEditor(controller, TestConfSetting.TEAR_DOWN_METHOD);
        tearDown.showUI();
    }

    /**
     * Launches window to show JUnit test header.
     */
    public void showTestHeader()
    {
        SetupEditor tearDown = new SetupEditor(controller, TestConfSetting.TEST_HEADER);
        tearDown.showUI();
    }
    
    public void showProjectConfiguration()
    {
        JFrame projectConfigurationWindow = new JFrame();
        ProjectConfigurationWindow projectConfigurationContent = 
                new ProjectConfigurationWindow(projectConfigurationWindow);
        
        
        projectConfigurationWindow.setContentPane(projectConfigurationContent);
        projectConfigurationWindow.setSize(591, 260);
        projectConfigurationWindow.setVisible(true);
    }

    /**
     * Updates the gui to show the next method.
     */
    public void nextMethod()
    {
        controller.nextMethod();
        this.updateExecutionPathEditor();
        highlightLine();
    }

    /**
     * Updates the gui to show the last method.
     */
    public void prevMethod()
    {
        controller.prevMethod();
        this.updateExecutionPathEditor();
        highlightLine();

    }

    /**
     * Saves the test currently visible in the test creator.
     */
    public void saveTestCreatorTest()
    {
        this.testCreator.saveTest();
    }

    /**
     * Shows an error message to the user when a syntax error occurs
     * in the source file.
     * @param errorMessage
     */
    public void showLanguageErrorMessage(String errorMessage)
    {
        String msg = "A Syntax Error Has Occurred:\n";
        msg += errorMessage + "\n";
        msg += "Please fix this error and then try again otherwise the tool "
                + "may have unexpected results!";

        JOptionPane.showMessageDialog(mainFrame, msg, "Parser Error", JOptionPane.ERROR_MESSAGE);

    }

    public void highlightLine()
    {
        this.codeViewer.highlightLine(controller.getCurrMethod());
    }

    public BranchGraphController getBasisPathController()
    {
        return branchPathController;
    }

    public void saveLastVisitedDirectory(File directoryPath) {
        this.directoryPath = directoryPath;
    }

    public File getLastVisitedDirectory() {
        return directoryPath;
    }
    
}
